home *** CD-ROM | disk | FTP | other *** search
- /* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Gmail Notifier code.
- *
- * The Initial Developer of the Original Code is
- * Doron Rosenberg.
- * Portions created by the Initial Developer are Copyright (C) 2004
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of the GNU General Public License Version 2 or later (the "GPL"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
- /*
- todo:
- - array.pop
- - nsITimer should not be a one-shot
- */
-
- const kGMSERVICE_CONTRACTID = "@mozilla.org/GMailNotifier;1"
- const kGMSERVICE_CID = Components.ID("7b69f823-6d18-4c7f-a4e5-c5c2507217b8");
- const nsIGMNotifierService = Components.interfaces.nsIGMNotifierService
- const nsIGMNotifierProgressListener = Components.interfaces.nsIGMNotifierProgressListener;
- const nsISupports = Components.interfaces.nsISupports;
-
- const kIOSERVICE_CONTRACTID = "@mozilla.org/network/io-service;1";
- const nsIIOService = Components.interfaces.nsIIOService;
-
- const nsICookieManager = Components.interfaces.nsICookieManager;
- const kCOOKIESERVICE_CONTRACTID = "@mozilla.org/cookieService;1";
-
- const kPSWDMANAGER_CONTRACTID = "@mozilla.org/passwordmanager;1";
- const nsIPasswordManagerInternal = Components.interfaces.nsIPasswordManagerInternal;
-
- const kTIMER_CONTRACTID = "@mozilla.org/timer;1";
- const nsITimer = Components.interfaces.nsITimer;
-
- // debug output
- const GM_DEBUG = false;
-
- function nsGMNotifierService() {
- this.listeners = new Array();
- this.updateTimer = null;
-
- this.unreadEmails = null;
- this.resetState = false;
- this.newEmails = 0;
- this.space_used_mb = null;
- this.space_used_percent = null;
-
- this.connectionPhase = 0;
- this.loggedIn = false;
-
- this.username = null;
- this.password = null;
-
- this.timeOut = 600000; // default to 10 mins
-
- this.prefBranch = null;
- this.stringBundle = null;
-
- this.notificationListenerID;
-
- var myThis = this;
- this.PrefChangeObserver = {
- observe: function(aSubject, aTopic, aData)
- {
- myThis.prefChanged(aData);
- }
- };
-
- this.logString = "";
-
- this.addObserver("gm-notifier", this.PrefChangeObserver);
- }
-
- /*
- *
- * Scriptable interfaces
- *
- */
-
- // login method
- nsGMNotifierService.prototype.initLogin = function (aUsername, aPassword, aListenerID) {
- gGMNotifierService.logItem("initLogin: aListenerID is " + aListenerID);
- gGMNotifierService.username = aUsername;
- gGMNotifierService.password = aPassword;
-
- gGMNotifierService.notificationListenerID = aListenerID;
-
- gGMNotifierService.talkToServer();
- }
-
- nsGMNotifierService.prototype.checkNow = function () {
- gGMNotifierService.talkToServer();
- }
-
- nsGMNotifierService.prototype.logout = function () {
- this.username = null;
- this.password = null;
-
- this.unreadEmails = null;
- this.newEmails = 0;
- this.space_used_mb = null;
- this.space_used_percent = null;
-
- if (this.updateTimer)
- this.updateTimer.cancel();
- this.updateTimer = null;
-
- this.loggedIn = false;
-
- //clear the login cookie
- try{
- var ios = Components.classes[kIOSERVICE_CONTRACTID].getService(nsIIOService);
- var cookMan = Components.classes[kCOOKIESERVICE_CONTRACTID].getService(nsICookieManager);
- cookMan.remove("gmail.google.com", "GV", "/", false);
- } catch(e){}
-
- this.pushStateChange(nsIGMNotifierProgressListener.LOGOUT);
- }
-
- // users can add listeners (nsIGMNotifierListener) here
- nsGMNotifierService.prototype.addListener = function(aListener) {
- // should we autologin?
- // make sure to only check for autologin the first time a listener has been
- // added, ie first browser window calls us.
- if ( (this.listeners.length == 0) && this.prefBranch &&
- this.prefBranch.getBoolPref("gm-notifier.autologin.enabled") ) {
- // autologin
- var defaultUser = this.prefBranch.getCharPref("gm-notifier.users.default");
- if (defaultUser) {
- this.username = defaultUser;
- this.password = this.getLoginDetails(this.username);
- this.talkToServer();
- }
- }
-
- this.listeners.push(aListener);
-
- // for every new listener added, push login state
- if (this.loggedIn)
- aListener.onStateChange(nsIGMNotifierProgressListener.LOGIN_SUCCESS);
- else
- aListener.onStateChange(nsIGMNotifierProgressListener.LOGOUT);
-
- return this.listeners.length;
- }
-
- nsGMNotifierService.prototype.removeListener = function(aListener) {
- var found = false;
- var run = 0;
-
- while (!found || (run < this.listeners.length)) {
- if (this.listeners[run] == aListener) {
- this.listeners[run] = null;
- found = true;
- }
- run++;
- }
- }
-
- nsGMNotifierService.prototype.getUnreadCount = function() {
- if (this.resetState)
- return 0;
- else
- return this.unreadEmails;
- }
-
- nsGMNotifierService.prototype.getNewCount = function() {
- if (this.resetState)
- return 0;
- else
- return this.newEmails;
- }
-
- nsGMNotifierService.prototype.getUsedMB = function() {
- return this.space_used_mb;
- }
-
- nsGMNotifierService.prototype.getSpaceUsed = function() {
- return this.space_used_percent;
- }
-
- nsGMNotifierService.prototype.getUserName = function() {
- return this.username;
- }
-
- nsGMNotifierService.prototype.setTimeout = function(aMinutes) {
- // convert to ms
- this.timeOut = (aMinutes * 60000);
-
- // set timer only if we are logged in
- if (this.loggedIn)
- this.setTimer();
- }
-
- /*
- *
- * Non-Scriptable interfaces
- *
- */
-
- nsGMNotifierService.prototype.pushStateChange = function(aState) {
- for (var run = 0; run < this.listeners.length; run++)
- if (this.listeners[run]) // can be null
- this.listeners[run].onStateChange(aState);
- }
-
- // timing stuff
- nsGMNotifierService.prototype.setTimer = function() {
- if (this.updateTimer) {
- this.updateTimer.cancel();
- } else {
- this.updateTimer = Components.classes[kTIMER_CONTRACTID]
- .createInstance(nsITimer);
- }
-
- this.updateTimer.initWithCallback(this, this.timeOut, nsITimer.TYPE_ONE_SHOT);
- }
-
- // nsITimer
- nsGMNotifierService.prototype.notify = function(aTimer) {
- this.talkToServer();
- }
-
- nsGMNotifierService.prototype.observer = function(aCallbackFunc) {
- return ({
- data : "",
-
- onStartRequest : function (aRequest, aContext) {
- this.data = "";
- },
-
- onDataAvailable : function (aRequest, aContext, aStream, aSourceOffset, aLength){
- var scriptableInputStream =
- Components.classes["@mozilla.org/scriptableinputstream;1"]
- .createInstance(Components.interfaces.nsIScriptableInputStream);
- scriptableInputStream.init(aStream);
-
- this.data += scriptableInputStream.read(aLength);
- },
-
- onStopRequest : function (aRequest, aContext, aStatus) {
- aCallbackFunc(this.data, aRequest);
- },
-
- QueryInterface : function(aIID) {
- if (aIID.equals(Components.interfaces.nsIStreamListener) ||
- aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
- aIID.equals(Components.interfaces.nsIAlertListener) ||
- aIID.equals(nsISupports))
- return this;
- throw Components.results.NS_NOINTERFACE;
- }
- }
- );
- }
-
- nsGMNotifierService.prototype.start = function (aURL, aPostData, aCookieData, aReferrer, aCallbackFunc){
-
- // the IO service
- var ioService = Components.classes[kIOSERVICE_CONTRACTID].getService(nsIIOService);
-
- // create an nsIURI
- var uri = ioService.newURI(aURL, null, null);
-
- //nsIInputStream
- var uploadStream = Components.classes["@mozilla.org/io/string-input-stream;1"]
- .createInstance(Components.interfaces.nsIStringInputStream);
-
- if (aPostData)
- uploadStream.setData(aPostData, aPostData.length);
-
- // get a channel for that nsIURI
- var channel = ioService.newChannelFromURI(uri);
-
- // get a httpchannel and make it a post
- var httpChannel = channel.QueryInterface(Components.interfaces.nsIHttpChannel);
-
- // set a referrer
- if (aReferrer) {
- var referrerUri = ioService.newURI(aReferrer, null, null);
- httpChannel.referrer = referrerUri;
- }
-
- if (aPostData) {
- var uploadChannel = channel.QueryInterface(Components.interfaces.nsIUploadChannel);
- uploadChannel.setUploadStream(uploadStream, "application/x-www-form-urlencoded", -1);
-
- // order important - setUploadStream resets to get/put
- httpChannel.requestMethod = "POST";
- }
-
- if (aCookieData){
- // httpChannel.setRequestHeader("Cookie", aCookieData, false);
- for (var run = 0; run < aCookieData.length; run++){
- httpChannel.setRequestHeader("Cookie", aCookieData[run], true);
- }
- }
-
- var observer = new this.observer(aCallbackFunc);
- channel.asyncOpen(observer, null);
- }
-
- // initiates talking to Gmail
- nsGMNotifierService.prototype.talkToServer = function () {
-
- if (!this.username || !this.password) {
- return;
- }
-
- this.resetState = false;
-
- this.connectionPhase = 0;
- this.pushStateChange(nsIGMNotifierProgressListener.LOGIN_INITIATED);
-
- var data = "service=mail&Email=" + encodeURIComponent(this.username)
- + "&Passwd=" + encodeURIComponent(this.password) +
- "&null=Sign%20in&continue=http://gmail.google.com/gmail";
-
- this.start("https://www.google.com/accounts/ServiceLoginBoxAuth", data, null,
- "https://www.google.com/", this.callback);
- }
-
- /*
- Phase Description
- 0 Before anything has happend
- 1 First connection
- ...
- */
-
- nsGMNotifierService.prototype.callback = function (aData, aRequest) {
- gGMNotifierService.connectionPhase++;
-
- switch (gGMNotifierService.connectionPhase) {
- case 1:
- var cookieData;
-
- // if no cookies sent, an exception is thrown
- try{
- //var httpChannel = aRequest.QueryInterface(Components.interfaces.nsIHttpChannel)
- //cookieData = httpChannel.getRequestHeader("cookie");
- } catch(e){}
-
- var val = aData.match(/="CheckCookie[^]+Html"/);
-
- if (!val) {
- // XXX - check if its an image request
-
- // failed to login
- gGMNotifierService.pushStateChange(nsIGMNotifierProgressListener.LOGIN_FAILED);
- return;
- }
-
- var url = val[0].substr(2, (val[0].length-3) );
- /* var val = aData.match(/var cookieVal= "([^"]+)";/); */
-
- gGMNotifierService.start("https://www.google.com/accounts/" + url,
- null, null, "https://www.google.com/", gGMNotifierService.callback);
- break;
-
- case 2:
- var val = aData.match(/replace\("[^]+"/);
-
- if (!val) {
- // failed to login
- gGMNotifierService.pushStateChange(nsIGMNotifierProgressListener.LOGIN_FAILED);
- return;
- }
-
- var url = val[0].substr(9, (val[0].length-1) )
- url = url.substr(0, (url.length-1) );
-
- gGMNotifierService.start(url, null, null, "https://www.google.com/", gGMNotifierService.callback);
- break;
-
- case 3:
- gGMNotifierService.start("https://gmail.google.com/gmail?search=adv&as_subset=unread&view=tl&start=0",
- null, null, "https://www.google.com/", gGMNotifierService.callback);
- break;
-
- case 4:
- var val = aData.match(/\["ds",.*\]/);
-
- if (!val) {
- var myVal = aData.match(/Captcha\?ctoken.*.com"/);
-
- // failed to login
- gGMNotifierService.pushStateChange(nsIGMNotifierProgressListener.LOGIN_FAILED);
- return;
- }
-
- var myArray = eval(val[0]);
- gGMNotifierService.logItem("GMail new mail check complete:");
- gGMNotifierService.logItem(" ::myArray[1] is " + myArray[1] + " unread is " + gGMNotifierService.unreadEmails);
-
- if ( (gGMNotifierService.unreadEmails != null) && (myArray[1] > gGMNotifierService.unreadEmails)) {
- gGMNotifierService.logItem(" New Unread Mail Found!");
- // new email
- gGMNotifierService.newEmails = (parseInt(myArray[1],10) - gGMNotifierService.unreadEmails);
- gGMNotifierService.pushStateChange(nsIGMNotifierProgressListener.NEW_MAIL);
- gGMNotifierService.newMailNotification(gGMNotifierService.newEmails);
- } else if (gGMNotifierService.unreadEmails == null) {
- // first time
- var unread = parseInt(myArray[1], 10);
- if (unread > 0) {
- gGMNotifierService.logItem(" New Mail Found!");
- gGMNotifierService.newEmails = unread;
- gGMNotifierService.unreadEmails = unread;
- gGMNotifierService.pushStateChange(nsIGMNotifierProgressListener.NEW_MAIL);
- gGMNotifierService.logItem(" -- amount of new mail is " + gGMNotifierService.newEmails);
- gGMNotifierService.logItem(" val[0] is " + val[0]);
- gGMNotifierService.logItem(" myArray[1] is " + myArray[1]);
- gGMNotifierService.newMailNotification(gGMNotifierService.newEmails);
- } else {
- gGMNotifierService.newEmails = 0;
- gGMNotifierService.unreadEmails = 0;
- }
- } else {
- gGMNotifierService.logItem(" No New Unread Mail Found!");
- gGMNotifierService.pushStateChange(nsIGMNotifierProgressListener.NO_NEW_MAIL);
- }
-
- gGMNotifierService.unreadEmails = parseInt(myArray[1],10);
-
- val = aData.match(/\["qu",.*\]/);
- myArray = eval(val[0]);
-
- gGMNotifierService.space_used_mb = myArray[1];
- gGMNotifierService.space_used_percent = myArray[3];
-
- gGMNotifierService.loggedIn = true;
-
- gGMNotifierService.pushStateChange(nsIGMNotifierProgressListener.LOGIN_SUCCESS);
- gGMNotifierService.setTimer();
- break;
- }
- }
-
- /*
- New mail notification
- */
- nsGMNotifierService.prototype.newMailNotification = function (aNewNum){
- this.logItem("New Mail Notification Init:");
-
- var isNotificationEnabled = this.prefBranch.getBoolPref("gm-notifier.ui.notification.enabled");
- this.logItem(" Is System Notification Enabled by user: " + isNotificationEnabled);
-
- if (isNotificationEnabled){
- var msg = this.getFormattedString("NotificationMsg", [aNewNum]);
-
- try {
- var alertService = Components.classes["@mozilla.org/alerts-service;1"]
- .getService(Components.interfaces.nsIAlertsService);
- if (alertService) {
- alertService.showAlertNotification("chrome://gm-notifier/content/gm-logo.png",
- this.getString("NotificationMsgTitle"), msg, true, "", this);
- this.logItem(" alertsService success.");
- } else {
- this.logItem(" alertsService failure: could not getService nsIAlertsService");
- }
- } catch(e) {
- this.logItem(" alertsService failure: " + e);
- }
- }
-
- // sound notifications
- var isSoundNotificationsEnabled = this.prefBranch.getBoolPref("gm-notifier.ui.soundnotification.enabled");
- this.logItem(" Is Sound Notification Enabled by user: " + isSoundNotificationsEnabled);
-
- if (isSoundNotificationsEnabled) {
- var soundUrl = this.prefBranch.getCharPref("gm-notifier.ui.soundnotification.uri");
-
- try {
- var sound = Components.classes["@mozilla.org/sound;1"]
- .createInstance(Components.interfaces.nsISound);
- if (soundUrl.indexOf("file://") == -1) {
- sound.playSystemSound(soundUrl);
- } else {
- var ioService = Components.classes[kIOSERVICE_CONTRACTID].getService(nsIIOService);
- var url = ioService.newURI(soundURL, null, null);
-
- sound.play(url)
- }
- } catch (e) {
- this.logItem(" Sound playing failed with: "+ e);
- }
- }
- }
-
- nsGMNotifierService.prototype.getStringBundle = function (){
- if (!this.stringBundle) {
- var strBundleService = Components.classes["@mozilla.org/intl/stringbundle;1"]
- .createInstance(Components.interfaces.nsIStringBundleService);
-
- this.stringBundle = strBundleService.createBundle("chrome://gm-notifier/locale/gm-notifier.properties");
- }
-
- return this.stringBundle;
- }
-
- nsGMNotifierService.prototype.getString = function (aName){
- return this.getStringBundle().GetStringFromName(aName);
- }
-
- nsGMNotifierService.prototype.getFormattedString = function (aName, aStrArray){
- return this.getStringBundle().formatStringFromName(aName, aStrArray, aStrArray.length);
- }
-
- // nsIObserver
- nsGMNotifierService.prototype.observe = function (aSubject, aTopic, aData){
- switch (aTopic) {
- case "alertfinished":
- break;
-
- case "alertclickcallback":
- this.showNotification();
- break;
- }
- }
-
- // nsIAlertsService - nsIAlertListener was deprecated and replaced with nsIObserver
- // This is to maintain 1.7 compatability.
- nsGMNotifierService.prototype.onAlertFinished = function (aCookie){
- }
-
- nsGMNotifierService.prototype.onAlertClickCallback = function (aCookie){
- this.showNotification();
- }
-
- nsGMNotifierService.prototype.showNotification = function (){
- // when the alert callback happens, we want to notify the listener that
- // initiated the server connection that the alert was clicked.
- // Simply pushing a state change to all listeners will result in the
- // infinite window open loop!
-
- this.logItem("Alert Clickback called:");
- this.logItem(" Notification Window is: (" + gGMNotifierService.notificationListenerID + ").");
-
- var run = 0;
- if (gGMNotifierService.notificationListenerID) {
- var done = false;
- while (!done && (run < this.listeners.length)) {
- this.logItem(" Item " + run + " has id (" + this.listeners[run].getID() + ")");
- if (this.listeners[run] && (this.listeners[run].getID() == this.notificationListenerID))
- done = true;
- else
- run++;
- }
- } else {
- // fallback
- while ((this.listeners[run] == null) && (run < this.listeners.length))
- run++;
-
- this.logItem(" No notification window found, call listener #" + run);
- }
-
- if (this.listeners[run])
- this.listeners[run].onStateChange(nsIGMNotifierProgressListener.LOAD_GMAIL);
- }
-
- /*
- *
- * Preference code
- *
- */
-
- nsGMNotifierService.prototype.getPrefBranch = function(){
- if (!this.prefBranch){
- this.prefBranch = Components.classes['@mozilla.org/preferences-service;1'];
- this.prefBranch = this.prefBranch.getService();
- this.prefBranch = this.prefBranch.QueryInterface(Components.interfaces.nsIPrefBranch);
- }
-
- return this.prefBranch;
- }
-
- nsGMNotifierService.prototype.prefChanged = function (aPrefName){
- switch(aPrefName){
- case "gm-notifier.update.interval":
- this.setTimeout(this.prefBranch.getIntPref("gm-notifier.update.interval"));
- break;
- }
- }
-
- nsGMNotifierService.prototype.addObserver = function(aDomain, aFunction){
- var myPrefs = this.getPrefBranch();
- var prefBranchInternal = myPrefs.QueryInterface(Components.interfaces.nsIPrefBranchInternal);
-
- if (prefBranchInternal)
- prefBranchInternal.addObserver(aDomain, aFunction, false);
- }
-
- nsGMNotifierService.prototype.getLoginDetails = function(aUsername){
- var url = "chrome://gm-notifier/";
-
- var passwordManager = Components.classes[kPSWDMANAGER_CONTRACTID]
- .createInstance(nsIPasswordManagerInternal);
- var host = {value:""};
- var user = {value:""};
- var password = {value:""};
-
- try {
- passwordManager.findPasswordEntry(url, aUsername, "", host, user, password);
- } catch(e){
- }
-
- return password.value;
- }
-
- nsGMNotifierService.prototype.getResetState = function() {
- return this.resetState;
- }
-
- nsGMNotifierService.prototype.setResetState = function(aResetState) {
- this.resetState = aResetState;
- gGMNotifierService.pushStateChange(nsIGMNotifierProgressListener.LOGIN_SUCCESS);
- }
-
- nsGMNotifierService.prototype.logItem = function(aLog) {
- this.logString += aLog + "|||";
- }
-
- nsGMNotifierService.prototype.getLog = function() {
- return this.logString;
- }
-
- nsGMNotifierService.prototype.test = function() {
- return this.g + " testing " + new Date().toString();
- }
-
- nsGMNotifierService.prototype.QueryInterface = function(iid) {
- if (!iid.equals(nsIGMNotifierService) &&
- !iid.equals(Components.interfaces.nsIAlertListener) &&
- !iid.equals(Components.interfaces.nsIObserver) &&
- !iid.equals(nsISupports))
- throw Components.results.NS_ERROR_NO_INTERFACE;
- return this;
- }
-
- var gGMNotifierService = new nsGMNotifierService();
-
- /**
- * JS XPCOM component registration goop:
- *
- * We set ourselves up to observe the xpcom-startup category. This provides
- * us with a starting point.
- */
-
- var nsGMNotifierServiceModule = new Object();
-
- nsGMNotifierServiceModule.registerSelf = function (compMgr, fileSpec, location, type) {
- compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
- compMgr.registerFactoryLocation(kGMSERVICE_CID,
- "nsGMNotifierService",
- kGMSERVICE_CONTRACTID,
- fileSpec,
- location,
- type);
- }
-
- nsGMNotifierServiceModule.getClassObject = function (compMgr, cid, iid) {
- if (!cid.equals(kGMSERVICE_CID))
- throw Components.results.NS_ERROR_NO_INTERFACE;
-
- if (!iid.equals(Components.interfaces.nsIFactory))
- throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
-
- return nsGMNotifierServiceFactory;
- }
-
- nsGMNotifierServiceModule.canUnload = function (compMgr) {
- // cleanup
- gGMNotifierService.listeners = null;
- if (gGMNotifierService.updateTimer)
- gGMNotifierService.updateTimer.cancel();
- gGMNotifierService.updateTimer = null;
-
- return true;
- }
-
- var nsGMNotifierServiceFactory = new Object();
-
- nsGMNotifierServiceFactory.createInstance = function (outer, iid) {
- if (outer != null)
- throw Components.results.NS_ERROR_NO_AGGREGATION;
-
- if (!iid.equals(nsIGMNotifierService) &&
- !iid.equals(Components.interfaces.nsIAlertListener) &&
- !iid.equals(nsISupports))
- throw Components.results.NS_ERROR_NO_INTERFACE;
-
- return gGMNotifierService;
- }
-
- function NSGetModule(compMgr, fileSpec) {
- return nsGMNotifierServiceModule;
- }
-